/*----------------------------------------------------------------------------*\
|
|						Public Interface to Muse Technology
|
|							     www.Muse.com
| Author : SunJun 
| Email : sundoom@msn.com
\*----------------------------------------------------------------------------*/

//////////////////////////////////////////////////////////////////////////
// $Id: MObject.h,v 1.1 2009/04/03 12:46:09 sunjun Exp $
//////////////////////////////////////////////////////////////////////////

#ifndef __MObject__
#define __MObject__

//////////////////////////////////////////////////////////////////////////

#if defined __cplusplus

//////////////////////////////////////////////////////////////////////////

#include <Muse.h>
#include <MReference.h>
#include <MVar.h>
#include <MProperty.h>

//////////////////////////////////////////////////////////////////////////

NAMESPACE_BEGIN

//////////////////////////////////////////////////////////////////////////	

	class API MObject;

	//////////////////////////////////////////////////////////////////////////
	// DISPATCH MAP HANDLING
	//////////////////////////////////////////////////////////////////////////
	
	#pragma pack(1)

	//////////////////////////////////////////////////////////////////////////

	// the member function of the dispatch
	typedef VOID (MObject::*MDISP_MFN)( const MVar* argv );

	// the arg function of the dispatch
	typedef VOID (*MDISP_AFN)( const VOID* pthis, MDISP_MFN mfn, const MVar* argv );	

	struct MDISP_MAP_ENTRY
	{
		const CHAR * name;
		MDISP_MFN mfn;
		MDISP_AFN afn;
	};

	struct MDISP_MAP
	{
		const MDISP_MAP* (STDCALL* getBaseDispatchMap)();
		const MDISP_MAP_ENTRY* entries;
	};

	#define MDECLARE_DISPATCH_MAP() \
		private: \
			static const MDISP_MAP __disp_map; \
			static const MDISP_MAP_ENTRY __disp_entries[]; \
		protected:\
			virtual const MDISP_MAP* getDispatchMap() const; \
		public: \
			static const MDISP_MAP* STDCALL getThisDispatchMap(); \

	#define MBEGIN_DISPATCH_MAP(theClass, baseClass) \
		const MDISP_MAP* STDCALL theClass::getThisDispatchMap() \
			{ return &theClass::__disp_map; } \
		const MDISP_MAP* theClass::getDispatchMap() const \
			{ return &theClass::__disp_map; } \
		const MDISP_MAP theClass::__disp_map = \
			{ &baseClass::getThisDispatchMap, &theClass::__disp_entries[0] }; \
		const MDISP_MAP_ENTRY theClass::__disp_entries[] = \
			{ \

	#define MEND_DISPATCH_MAP() \
		{ NULL, (MDISP_MFN)NULL, (MDISP_AFN)NULL } }; \

	#define MDISPATCH_FUNCTION(theClass, name, method, afn) \
		{ name, (MDISP_MFN)(VOID (theClass::*)(const MVar *argv))&method, (MDISP_AFN)afn },

	//////////////////////////////////////////////////////////////////////////
	// DISPATCH CALL BACK
	//////////////////////////////////////////////////////////////////////////

	template< typename R > struct DCB	// dispatch call back
	{
		template< typename O >
		INLINE static VOID Call( O* object, R (O::*func)(), MVar *argv ) 
		{R ret = (object->*func)(); argv[0] = ret;}
		template< typename O, typename A1 >
		INLINE static VOID Call( O* object, R (O::*func)(A1), MVar *argv ) 
		{R ret = (object->*func)( (A1)argv[1].value((A1)0) ); argv[0] = ret;}
		template< typename O, typename A1, typename A2 >
		INLINE static VOID Call( O* object, R (O::*func)(A1,A2), MVar *argv ) 
		{R ret = (object->*func)( (A1)argv[1].value((A1)0), (A2)argv[2].value((A2)0) ); argv[0] = ret;}
		template< typename O, typename A1, typename A2, typename A3 >
		INLINE static VOID Call( O* object, R (O::*func)(A1,A2,A3), MVar *argv ) 
		{R ret = (object->*func)( (A1)argv[1].value((A1)0), (A2)argv[2].value((A2)0), (A3)argv[3].value((A3)0) ); argv[0] = ret;}
		template< typename O, typename A1, typename A2, typename A3, typename A4 >
		INLINE static VOID Call( O* object, R (O::*func)(A1,A2,A3,A4), MVar *argv ) 
		{R ret = (object->*func)( (A1)argv[1].value((A1)0), (A2)argv[2].value((A2)0), (A3)argv[3].value((A3)0), (A4)argv[4].value((A4)0) ); argv[0] = ret;}
		template< typename O, typename A1, typename A2, typename A3, typename A4, typename A5 >
		INLINE static VOID Call( O* object, R (O::*func)(A1,A2,A3,A4,A5), MVar *argv ) 
		{R ret = (object->*func)( (A1)argv[1].value((A1)0), (A2)argv[2].value((A2)0), (A3)argv[3].value((A3)0), (A4)argv[4].value((A4)0), (A5)argv[5].value((A5)0) ); argv[0] = ret;}
		template< typename O, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6 >
		INLINE static VOID Call( O* object, R (O::*func)(A1,A2,A3,A4,A5,A6), MVar *argv ) 
		{R ret = (object->*func)( (A1)argv[1].value((A1)0), (A2)argv[2].value((A2)0), (A3)argv[3].value((A3)0), (A4)argv[4].value((A4)0), (A5)argv[5].value((A5)0), (A6)argv[6].value((A6)0) ); argv[0] = ret;}
		
		INLINE static VOID Call( R (*func)(), MVar *argv ) 
		{R ret = (*func)(); argv[0] = ret;}
		template< typename A1 >
		INLINE static VOID Call( R (*func)(A1), MVar *argv ) 
		{R ret = (*func)( (A1)argv[1].value((A1)0) ); argv[0] = ret;}
		template< typename A1, typename A2 >
		INLINE static VOID Call( R (*func)(A1,A2), MVar *argv ) 
		{R ret = (*func)( (A1)argv[1].value((A1)0), (A2)argv[2].value((A2)0) ); argv[0] = ret;}
		template< typename A1, typename A2, typename A3 >
		INLINE static VOID Call( R (*func)(A1,A2,A3), MVar *argv ) 
		{R ret = (*func)( (A1)argv[1].value((A1)0), (A2)argv[2].value((A2)0), (A3)argv[3].value((A3)0) ); argv[0] = ret;}
		template< typename A1, typename A2, typename A3, typename A4 >
		INLINE static VOID Call( R (*func)(A1,A2,A3,A4), MVar *argv ) 
		{R ret = (*func)( (A1)argv[1].value((A1)0), (A2)argv[2].value((A2)0), (A3)argv[3].value((A3)0), (A4)argv[4].value((A4)0) ); argv[0] = ret;}
		template< typename A1, typename A2, typename A3, typename A4, typename A5 >
		INLINE static VOID Call( R (*func)(A1,A2,A3,A4,A5), MVar *argv )
		{R ret = (*func)( (A1)argv[1].value((A1)0), (A2)argv[2].value((A2)0), (A3)argv[3].value((A3)0), (A4)argv[4].value((A4)0), (A5)argv[5].value((A5)0) ); argv[0] = ret;}
		template< typename A1, typename A2, typename A3, typename A4, typename A5, typename A6 >
		INLINE static VOID Call( R (*func)(A1,A2,A3,A4,A5,A6), MVar *argv )
		{R ret = (*func)( (A1)argv[1].value((A1)0), (A2)argv[2].value((A2)0), (A3)argv[3].value((A3)0), (A4)argv[4].value((A4)0), (A5)argv[5].value((A5)0), (A6)argv[6].value((A6)0) ); argv[0] = ret;}
	};

	template<> struct DCB< VOID > 
	{
		template< typename O >
		INLINE static VOID Call( O* object, VOID (O::*func)(), MVar *argv ) 
		{(object->*func)();argv[0] = MVar();}
		template< typename O, typename A1 >
		INLINE static VOID Call( O* object, VOID (O::*func)(A1), MVar *argv ) 
		{(object->*func)( (A1)argv[1].value((A1)0) ); argv[0] = MVar();}
		template< typename O, typename A1, typename A2 >
		INLINE static VOID Call( O* object, VOID (O::*func)(A1,A2), MVar *argv ) 
		{(object->*func)( (A1)argv[1].value((A1)0), (A2)argv[2].value((A2)0) ); argv[0] = MVar();}
		template< typename O, typename A1, typename A2, typename A3 >
		INLINE static VOID Call( O* object, VOID (O::*func)(A1,A2,A3), MVar *argv ) 
		{(object->*func)( (A1)argv[1].value((A1)0), (A2)argv[2].value((A2)0), (A3)argv[3].value((A3)0) ); argv[0] = MVar();}
		template< typename O, typename A1, typename A2, typename A3, typename A4 >
		INLINE static VOID Call( O* object, VOID (O::*func)(A1,A2,A3,A4), MVar *argv ) 
		{(object->*func)( (A1)argv[1].value((A1)0), (A2)argv[2].value((A2)0), (A3)argv[3].value((A3)0), (A4)argv[4].value((A4)0) ); argv[0] = MVar(); }
		template< typename O, typename A1, typename A2, typename A3, typename A4, typename A5 >
		INLINE static VOID Call( O* object, VOID (O::*func)(A1,A2,A3,A4,A5), MVar *argv ) 
		{(object->*func)( (A1)argv[1].value((A1)0), (A2)argv[2].value((A2)0), (A3)argv[3].value((A3)0), (A4)argv[4].value((A4)0), (A5)argv[5].value((A5)0) );argv[0] = MVar();}	
		template< typename O, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6 >
		INLINE static VOID Call( O* object, VOID (O::*func)(A1,A2,A3,A4,A5,A6), MVar *argv ) 
		{(object->*func)( (A1)argv[1].value((A1)0), (A2)argv[2].value((A2)0), (A3)argv[3].value((A3)0), (A4)argv[4].value((A4)0), (A5)argv[5].value((A5)0), (A6)argv[6].value((A6)0) );argv[0] = MVar();}	

		INLINE static VOID Call( VOID (*func)(), MVar *argv ) 
		{(*func)();argv[0] = MVar();}
		template< typename A1 >
		INLINE static VOID Call( VOID (*func)(A1), MVar *argv ) 
		{(*func)( (A1)argv[1].value((A1)0) );argv[0] = MVar();}
		template< typename A1, typename A2 >
		INLINE static VOID Call( VOID (*func)(A1,A2), MVar *argv ) 
		{(*func)( (A1)argv[1].value((A1)0), (A2)argv[2].value((A2)0) );argv[0] = MVar();}
		template< typename A1, typename A2, typename A3 >
		INLINE static VOID Call( VOID (*func)(A1,A2,A3), MVar *argv ) 
		{(*func)( (A1)argv[1].value((A1)0), (A2)argv[2].value((A2)0), (A3)argv[3].value((A3)0) );argv[0] = MVar();}
		template< typename A1, typename A2, typename A3, typename A4 >
		INLINE static VOID Call( VOID (*func)(A1,A2,A3,A4), MVar *argv ) 
		{(*func)( (A1)argv[1].value((A1)0), (A2)argv[2].value((A2)0), (A3)argv[3].value((A3)0), (A4)argv[4].value((A4)0) );argv[0] = MVar();}
		template< typename A1, typename A2, typename A3, typename A4, typename A5 >
		INLINE static VOID Call( VOID (*func)(A1,A2,A3,A4,A5), MVar *argv ) 
		{(*func)( (A1)argv[1].value((A1)0), (A2)argv[2].value((A2)0), (A3)argv[3].value((A3)0), (A4)argv[4].value((A4)0), (A5)argv[5].value((A5)0) );argv[0] = MVar();}
		template< typename A1, typename A2, typename A3, typename A4, typename A5, typename A6 >
		INLINE static VOID Call( VOID (*func)(A1,A2,A3,A4,A5,A6), MVar *argv ) 
		{(*func)( (A1)argv[1].value((A1)0), (A2)argv[2].value((A2)0), (A3)argv[3].value((A3)0), (A4)argv[4].value((A4)0), (A5)argv[5].value((A5)0), (A6)argv[6].value((A6)0) );argv[0] = MVar();}
	};

	template< typename R >
	INLINE VOID DARGFN0( const VOID* pthis, MDISP_MFN mfn, MVar *argv, R (*null_func)() = NULL )
	{R (MObject::*func)() = (R (MObject::*)())mfn; DCB<R>::Call( (MObject*)pthis, func, argv );}
	template< typename R, typename A1 >
	INLINE VOID DARGFN1( const VOID* pthis, MDISP_MFN mfn, MVar *argv, R (*null_func)(A1) = NULL )
	{R (MObject::*func)(A1) = (R (MObject::*)(A1))mfn;DCB<R>::Call( (MObject*)pthis, func, argv );}
	template< typename R, typename A1, typename A2 >
	INLINE VOID DARGFN2( const VOID* pthis, MDISP_MFN mfn, MVar *argv, R (*null_func)(A1,A2) = NULL )
	{R (MObject::*func)(A1,A2) = (R (MObject::*)(A1,A2))mfn;DCB<R>::Call( (MObject*)pthis, func, argv );}
	template< typename R, typename A1, typename A2, typename A3 >
	INLINE VOID DARGFN3( const VOID* pthis, MDISP_MFN mfn, MVar *argv, R (*null_func)(A1,A2,A3) = NULL )
	{R (MObject::*func)(A1,A2,A3) = (R (MObject::*)(A1,A2,A3))mfn;DCB<R>::Call( (MObject*)pthis, func, argv );}
	template< typename R, typename A1, typename A2, typename A3, typename A4 >
	INLINE VOID DARGFN4( const VOID* pthis, MDISP_MFN mfn, MVar *argv, R (*null_func)(A1,A2,A3,A4) = NULL )
	{R (MObject::*func)(A1,A2,A3,A4) = (R (MObject::*)(A1,A2,A3,A4))mfn;DCB<R>::Call( (MObject*)pthis, func, argv );}
	template< typename R, typename A1, typename A2, typename A3, typename A4, typename A5 >
	INLINE VOID DARGFN5( const VOID* pthis, MDISP_MFN mfn, MVar *argv, R (*null_func)(A1,A2,A3,A4,A5) = NULL )
	{R (MObject::*func)(A1,A2,A3,A4,A5) = (R (MObject::*)(A1,A2,A3,A4,A5))mfn;DCB<R>::Call( (MObject*)pthis, func, argv );}
	template< typename R, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6 >
	INLINE VOID DARGFN6( const VOID* pthis, MDISP_MFN mfn, MVar *argv, R (*null_func)(A1,A2,A3,A4,A5,A6) = NULL )
	{R (MObject::*func)(A1,A2,A3,A4,A5,A6) = (R (MObject::*)(A1,A2,A3,A4,A5,A6))mfn;DCB<R>::Call( (MObject*)pthis, func, argv );}

	template< typename R >
	INLINE MDISP_AFN DARG0( VOID (*func)(const VOID* pthis, MDISP_MFN mfn, MVar *argv, R (*null_func)() ) ) { return (MDISP_AFN)func; }
	template< typename R, typename A1 >
	INLINE MDISP_AFN DARG1( VOID (*func)(const VOID* pthis, MDISP_MFN mfn, MVar *argv, R (*null_func)(A1) ) ) { return (MDISP_AFN)func; }
	template< typename R, typename A1, typename A2 >
	INLINE MDISP_AFN DARG2( VOID (*func)(const VOID* pthis, MDISP_MFN mfn, MVar *argv, R (*null_func)(A1,A2) ) ) { return (MDISP_AFN)func; }
	template< typename R, typename A1, typename A2, typename A3 >
	INLINE MDISP_AFN DARG3( VOID (*func)(const VOID* pthis, MDISP_MFN mfn, MVar *argv, R (*null_func)(A1,A2,A3) ) ) { return (MDISP_AFN)func; }
	template< typename R, typename A1, typename A2, typename A3, typename A4 >
	INLINE MDISP_AFN DARG4( VOID (*func)(const VOID* pthis, MDISP_MFN mfn, MVar *argv, R (*null_func)(A1,A2,A3,A4) ) ) { return (MDISP_AFN)func; }
	template< typename R, typename A1, typename A2, typename A3, typename A4, typename A5 >
	INLINE MDISP_AFN DARG5( VOID (*func)(const VOID* pthis, MDISP_MFN mfn, MVar *argv, R (*null_func)(A1,A2,A3,A4,A5) ) ) { return (MDISP_AFN)func; }
	template< typename R, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6 >
	INLINE MDISP_AFN DARG6( VOID (*func)(const VOID* pthis, MDISP_MFN mfn, MVar *argv, R (*null_func)(A1,A2,A3,A4,A5,A6) ) ) { return (MDISP_AFN)func; }

	template< typename R >
	INLINE VOID ARGFN0( VOID* func_addr, MVar *argv, R (*null_func)() = NULL )
	{ R (*func)() = (R (*)())func_addr; DCB<R>::Call( func, argv ); }
	template< typename R, typename A1 >
	INLINE VOID ARGFN1( VOID* func_addr, MVar *argv, R (*null_func)(A1) = NULL )
	{ R (*func)(A1) = (R (*)(A1))func_addr; DCB<R>::Call( func, argv ); }
	template< typename R, typename A1, typename A2 >
	INLINE VOID ARGFN2( VOID* func_addr, MVar *argv, R (*null_func)(A1,A2) = NULL )
	{ R (*func)(A1,A2) = (R (*)(A1,A2))func_addr; DCB<R>::Call( func, argv ); }
	template< typename R, typename A1, typename A2, typename A3 >
	INLINE VOID ARGFN3( VOID* func_addr, MVar *argv, R (*null_func)(A1,A2,A3) = NULL )
	{ R (*func)(A1,A2,A3) = (R (*)(A1,A2,A3))func_addr; DCB<R>::Call( func, argv ); }
	template< typename R, typename A1, typename A2, typename A3, typename A4 >
	INLINE VOID ARGFN4( VOID* func_addr, MVar *argv, R (*null_func)(A1,A2,A3,A4) = NULL )
	{ R (*func)(A1,A2,A3,A4) = (R (*)(A1,A2,A3,A4))func_addr; DCB<R>::Call( func, argv ); }
	template< typename R, typename A1, typename A2, typename A3, typename A4, typename A5 >
	INLINE VOID ARGFN5( VOID* func_addr, MVar *argv, R (*null_func)(A1,A2,A3,A4,A5) = NULL )
	{ R (*func)(A1,A2,A3,A4,A5) = (R (*)(A1,A2,A3,A4,A5))func_addr; DCB<R>::Call( func, argv ); }
	template< typename R, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6 >
	INLINE VOID ARGFN6( VOID* func_addr, MVar *argv, R (*null_func)(A1,A2,A3,A4,A5,A6) = NULL )
	{ R (*func)(A1,A2,A3,A4,A5,A6) = (R (*)(A1,A2,A3,A4,A5,A6))func_addr; DCB<R>::Call( func, argv ); }

	template< typename R > 
	INLINE U32 ARG0( VOID (*func)(VOID* func_addr, MVar *argv, R (*null_func)() ) ) { return (U32)func; }
	template< typename R, typename A1 >
	INLINE U32 ARG1( VOID (*func)(VOID* func_addr, MVar *argv, R (*null_func)(A1) ) ) { return (U32)func; }
	template< typename R, typename A1, typename A2 >
	INLINE U32 ARG2( VOID (*func)(VOID* func_addr, MVar *argv, R (*null_func)(A1,A2) ) ) { return (U32)func; }
	template< typename R, typename A1, typename A2, typename A3 >
	INLINE U32 ARG3( VOID (*func)(VOID* func_addr, MVar *argv, R (*null_func)(A1,A2,A3) ) ) { return (U32)func; }
	template< typename R, typename A1, typename A2, typename A3, typename A4 >
	INLINE U32 ARG4( VOID (*func)(VOID* func_addr, MVar *argv, R (*null_func)(A1,A2,A3,A4) ) ) { return (U32)func; }
	template< typename R, typename A1, typename A2, typename A3, typename A4, typename A5 >
	INLINE U32 ARG5( VOID (*func)(VOID* func_addr, MVar *argv, R (*null_func)(A1,A2,A3,A4,A5) ) ) { return (U32)func; }
	template< typename R, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6 >
	INLINE U32 ARG6( VOID (*func)(VOID* func_addr, MVar *argv, R (*null_func)(A1,A2,A3,A4,A5,A6) ) ) { return (U32)func; }

	//////////////////////////////////////////////////////////////////////////

	#define MAX_NUM_ARG		6

	//////////////////////////////////////////////////////////////////////////

	/*
	ARG0<VOID>(&ARGFN0);
	ARG1<VOID,F64>(&ARGFN1);
	ARG5<VOID,F64,F64,F64,F64,F64>(&ARGFN5);
	
	DARG0<CHAR*>(&DARGFN0);
	DARG1<VOID,CHAR*>(&DARGFN1);
	DARG5<CHAR*,F64,F64,F64,F64,F64>(&DARGFN5);
	*/

	//////////////////////////////////////////////////////////////////////////

	typedef MObject* (STDCALL*MCFN)();
	#define MDECLARE_DYNCREATOR()						\
		public:												\
			static MObject* STDCALL creator();				\
			virtual const CHAR* classname() const;

	#define MIMPLEMENT_DYNCREATOR(class_name)			\
		MObject* STDCALL class_name::creator()				\
		{ return MNEW(class_name); }						\
		INLINE const CHAR* class_name::classname() const	\
		{ return #class_name; }

	//////////////////////////////////////////////////////////////////////////

	#pragma pack()

	//////////////////////////////////////////////////////////////////////////

	// base class from providing object.
	class API MObject : public virtual MReference
	{
	public:
		MObject();

		virtual ~MObject();

		// object's invoke method for the external.
		INLINE BOOL invoke( const CHAR* name, const MVar *argv );

		// object's property method.
		INLINE VOID property( const CHAR* prop_name, const MProperty* prop_ptr );
		INLINE const MProperty* property( const CHAR* prop_name ) const;

		// declare the dynamic creator
		MDECLARE_DYNCREATOR();		

		// declare the dispatch map
		MDECLARE_DISPATCH_MAP()

	private:
		std::map<Str, MPropertyPtr>mPropMap;
	};

	//////////////////////////////////////////////////////////////////////////

	typedef MPtr<MObject>MObjectPtr;

//////////////////////////////////////////////////////////////////////////

NAMESPACE_END

//////////////////////////////////////////////////////////////////////////

#endif // __cplusplus

//////////////////////////////////////////////////////////////////////////

#endif // __MObject__

//////////////////////////////////////////////////////////////////////////
